
fenData=[[100,2],[5000,2],[50,10],[400,5],[7000,2]]
fenData=[[100,2],[5000,2],[50,10],[400,5]]
fenData=[[100,2],[5000,2],[50,10],[399.5,5]]
fenData=[[100,2],[5000,2],[50,10],[399.51,5]]
fenData=[[100,2],[5000,2],[50,10],[399.5145,5]]
fenData=[[100,2],[5000.314,2],[50,10],[399.5145,5]]
fenData=[[100,2],[5000.314,2],[50,10],[399.5145,5],[7000.315,2],[5500,3]]
fenData=[[100,2],[5000.314,2],[50,10],[399.5145,5],[7000.315,2]]
fenData=[[100,2],[5000.314,2],[50,10],[399.5145,5],[7000,2]]
// FenData=[[5000, 2], [400, 5], [100, 2], [50, 10]]
// FenData=[ [ 5000, 400, 50 ], [ 5000, 400, 50 ], [ 400, 400, 400, 100, 100, 50, 50, 50, 50, 50, 50, 50, 50 ] ]




/**
 * 断料类(分料清单子二维数组,分段长度,损耗长度,料总长度,)
 * @param {Array} fenData - 分料清单子二维数组
 * @param {Number} fenDuanChangDu - 分段长度
 * @param {Number} sunHaoChangDu - 损耗长度
 * @param {Number} liaoZongChangDu - 料总长度(默认6000mm,不参与运算只做显示)
 * ver:1.0.4
 * JianPF 
 * 372191242@qq.com
 * 2024年12月3日23:37:13
 * 2024年12月4日21:56:26
 * ...
 */
class duanLiao{
    constructor(fenData,fenDuanChangDu=5500,sunHaoChangDu=3,liaoZongChangDu=6000){
        this.liaoZongChangDu=liaoZongChangDu;
        this.fenDuanChangDu=fenDuanChangDu;
        this.sunHaoChangDu=sunHaoChangDu;
        this.fenDataSour=this.deepCopy(fenData);
        this.fenData=this.deepCopy(fenData);
        // ---
        this.fenDuanBiao=[];
        this.tiaoDuanBiao=[];
        this.wuFaDuanBiao=[];
        this.yuLiao=this.fenDuanChangDu;
        this.selectA=0;
        this.jianShu=this.getJianShu(this.fenData);
        this.yujianShu=this.jianShu;
        // 全过程
        //初始化,分料清单,用降序排序方法
        this.sortArray2D(this.fenData);
    }


    // 初始化功能
    reset(fenData=this.fenDataSour,fenDuanChangDu=this.fenDuanChangDu,sunHaoChangDu=this.sunHaoChangDu,liaoZongChangDu=this.liaoZongChangDu){
        this.liaoZongChangDu=liaoZongChangDu;
        this.fenDuanChangDu=fenDuanChangDu;
        this.sunHaoChangDu=sunHaoChangDu;
        this.fenDataSour=this.deepCopy(fenData);
        this.fenData=this.deepCopy(fenData);
        // ---
        this.fenDuanBiao=[];
        this.tiaoDuanBiao=[];
        this.wuFaDuanBiao=[];
        this.yuLiao=this.fenDuanChangDu;
        this.selectA=0;
        this.jianShu=this.getJianShu(this.fenData);
        this.yujianShu=this.jianShu;
    }

    run(){
        // 断料全部
        this.getAll();
        // 断料追加余料值
        this.getAllAddYuLiaoBiao();
        // 无法断料的分出来
        this.getwuFaDuanBiao();
        // 无法断料的加到分料表中
        this.getWuFaBiaoAddFenDuanBiao();
        console.log('run()完成,分段长度:',this.fenDuanChangDu,'需要条数:',this.fenDuanBiao.length);
        return this.fenDuanBiao;
    }
    run2(){
        console.log('run2()完成,分段长度:',this.fenDuanChangDu,'需要条数:',this.fenDuanBiao.length);
        this.getHuiZhongFenDuanBiao();
        return this.fenDuanBiao;
    }

    // 汇总模式
    getHuiZhongFenDuanBiao(fenDuanBiao=this.fenDuanBiao){
        // console.log('getHuiZhongFenDuanBiao');
        let len=fenDuanBiao.length;
        // 判断是否有值
        if(len>0){
            // console.log('fenDuanBiao.length>0');
            // 判断是否子数组可变已经分段了的2模式
            if(this.checkArrayStructure(fenDuanBiao)==2){
                console.log('执行汇总模式');
                console.log(this.getFenDuanHuiZhong(fenDuanBiao[0]));
                for(var i=0;i<len;i++){
                    fenDuanBiao[i]=this.getFenDuanHuiZhong(fenDuanBiao[i])
                }
            }
        }
    }
    
    // 获取分段追加预料长度
    getWuFaBiaoAddFenDuanBiao(fenData=this.fenData){
        
        if(this.wuFaDuanBiao.length>0){
            this.fenDuanBiao.unshift(this.wuFaDuanBiao);
        }
    }

    // 获取无法分段的数据到无法分段的表中
    getwuFaDuanBiao(fenData=this.fenData,fenDuanChangDu=this.fenDuanChangDu){
        for (var i = 0; i < fenData.length; i++) {
            //console.log('fenData的第几个:',i);
            var subArray = fenData[i];
            // 优先判断料是否>分段长度(不是余料长度)
            if (subArray[0] > fenDuanChangDu && subArray[1] > 0) {
                for (var iv=0;iv<subArray[1];iv++)
                {
                    this.wuFaDuanBiao.push(subArray[0]);
                    //console.log("转移无法分段的值:",subArray[0])
                    // console.log(this.wuFaDuanBiao)
                }
                subArray[1]=0;
            } 
        }
    }


    // ---步骤1功能---
    
    
    // 获取所有分段件数记录
    getAll(){
        // 循环+2次分别是最后分段表追加空数组清除用
        for(var i=0;i<=this.jianShu+2;i++){
            this.getOne();
        }
    // 获取一次分段记录
    }
    // 获取一件
    getOne(){
            //取出一个值,并记录到分段表中---这里使用2个重要变量
            this.selectA=this.getFenData(this.fenData,this.yuLiao)
            //console.log("取出一次:",this.selectA);
            // console.log(this.fenData);
            // 判断是否取出成功
            if (this.selectA>0){
                // 临时记录到条断表中---重点在这里
                this.tiaoDuanBiao.push(this.selectA);
                // 扣除预料的长度+损耗长度
                this.yuLiao-=(this.selectA+this.sunHaoChangDu);
                // 剩余件数自减1
                this.yujianShu--;
                // console.log('selectA>0',this.selectA)
                // 特级处理,取出长度和余料长度一样
                if(this.yuLiao<0){
                    // console.log('取出长度和余料长度一样',this.yuLiao);
                    // 判断条断表是否有数值才追加到分段表中
                    if(this.tiaoDuanBiao.length>0)
                    {
                        // 追加到分段表中
                        this.fenDuanBiao.push(this.tiaoDuanBiao);
                        // 清空条断表
                        this.tiaoDuanBiao=[];
                        // 重置预料为分段长度
                        this.yuLiao=this.fenDuanChangDu;
                    }
                }
            }
            // 否则,追加到分段表中,重置余料长度,准备下一段
            else if(this.selectA<0){
                // console.log('selectA<0',this.selectA)
                // 判断条断表是否有数值才追加到分段表中
                if(this.tiaoDuanBiao.length>0)
                {
                    // 追加到分段表中
                    this.fenDuanBiao.push(this.tiaoDuanBiao);
                    // 清空条断表
                    this.tiaoDuanBiao=[];
                    // 重置预料为分段长度
                    this.yuLiao=this.fenDuanChangDu;
                }
                else{
                    // console.log('分段完成',this)
                }
            }
            else if(this.selectA==0){
                //console.log('selectA==0',this.selectA)
                // 退出循环
            }  
            // console.log(this.fenData);
            // 判断分段表是否有多余的空格
    }

    // 获取一个数出来处理
    //返回一个比yuLiao余料内的尺寸值并给数量的子数组减一(数组必须先执行降序排)
    getFenData(fenData=this.fenData,yuLiao=this.yuLiao){
        // 取出标志
        let select=-1;
        // 过长的分段数
        let guoChangFenDuanChangDu=0;
        for (var i = 0; i < fenData.length; i++) {
            var subArray = fenData[i];
            // 优先判断料是否>分段长度(不是预料长度),跳过当前
            if (subArray[0] > this.fenDuanChangDu && subArray[1] > 0) {
                // 记录过长的分段数
                guoChangFenDuanChangDu++;
                //console.log('料过长:',subArray,'余料剩余:',yuLiao);
                continue;
            } 
            // 判断
            if (subArray[0] <= yuLiao && subArray[1] > 0) {
                // 找到满足条件的子数组
                subArray[1] -= 1; // 将第二个值减一
                // select = subArray[0]; //获取长度
                // 四舍五入,直接向上取值,不要小数点
                select = Math.ceil(subArray[0]); //获取长度
                return select;
            }
        }
        //返回-1取出失败
        //console.log('取出失败,过长数:',guoChangFenDuanChangDu);
        return select;
    }
    
    
    
    // ---步骤2功能---



    // 获取追加分段表的预料
    getAllAddYuLiaoBiao(fenDuanBiao=this.fenDuanBiao,yuLiao=this.yuLiao,sunHaoChangDux=this.sunHaoChangDu){
        let len=fenDuanBiao.length;
        // 判断分段表是否有数据,有就替代修改子数组
        if(len>0){
            for(var i=0;i<len;i++){
                let yuLiaoChangD=this.getFenDuanAddYuLiao(fenDuanBiao[i],yuLiao,sunHaoChangDux);

            }
        }
    }

    // 获取分段追加余料长度
    getFenDuanAddYuLiao(arrx,yuLiaox=this.fenDuanChangDu,sunHaoChangDux=this.sunHaoChangDu){
        let YuLiaoChang=this.getFenDuanYuLiaoChang(arrx,yuLiaox,sunHaoChangDux);
        // 判断余料长度和断料长度不一样才有余料值
        if(YuLiaoChang!=0){
            // console.log('YuLiaoChang!=0',YuLiaoChang);
            arrx.push(YuLiaoChang);
            // 查看结果OK
            // console.log(arrx);
        }
        return YuLiaoChang;
    }

    // 获取分段预料长度
    getFenDuanYuLiaoChang(arrx,yuLiao=this.fenDuanChangDu,sunHaoChangDu=3){
        let sum=this.getArrSum(arrx);
        let sunHaoChangDuShu=0;
        let yuLiaoChang=0;
        if(sum==yuLiao){
            return 0;
        }
        else{
            sunHaoChangDuShu=arrx.length*sunHaoChangDu;
            yuLiaoChang=yuLiao-sum-sunHaoChangDuShu;
            //console.log('yuLiao=',yuLiao,'sum:',sum,'sunHaoChangDuShu:',sunHaoChangDuShu,'yuLiaoChang:',yuLiaoChang)
        }
        return yuLiaoChang;
    }
    

    // ---功能部分---


    // 获取断料的所有料数量
    getJianShu(fenData=this.fenData){
        let jianShu=0;
        for (var i = 0; i < fenData.length; i++) {
            var subArray = fenData[i];
            // 判断
            if (subArray[1] > 0) {
                jianShu+=subArray[1];
            }
        }
        return jianShu;
    }

    // 数组求和方法
    getArrSum(arrx){
        return arrx.reduce(function(accumulator, currentValue) {
            return accumulator + currentValue;
        }, 0); // 初始值为0
    }

    // 降序排序
    sortArray2D(fenData=this.fenData){
        fenData.sort(function(a, b) {
            // a和b都是FenData中的子数组
            // 我们根据子数组的第一个元素来比较它们的顺序
            return b[0] - a[0]; // 从大到小排序
        });
    }

    // 获取数组汇总列表
    getFenDuanHuiZhong(arrx){
        let arrK = arrx.reduce(function(accumulator, currentValue) {
            // 检查accumulator中是否已经有当前值的记录
            var found = accumulator.find(function(element) {
                return element[0] === currentValue;
            });
            
            if (found) {
                // 如果已经有记录，则增加计数
                found[1]++;
            } else {
                // 如果没有记录，则添加一个新的记录
                accumulator.push([currentValue, 1]);
            }
            return accumulator;
        }, []); // 初始值为一个空数组
        return arrK;
    }
// -----------
    /**
     * 判断数组结构并返回标识
     * @param {Array} arr - 要判断的数组
     * @returns {number} - 返回1=[[长度,数量]], 2=[[长度,长度,长度]], 或3=[[[长度,数量],...],[[长度,数量],...]]作为数组结构的标识
     * 百度飞桨生成2024年12月4日21:42:41@JianPF
     */
    checkArrayStructure(arr) {
        // 检查是否为结构1：a=[[1000,2],[400,4],...]
        function isStructure1(arr) {
            return arr.every(subArr => subArr.length === 2);
        }

        // 检查是否为结构2：a=[[1234,567,89,10,1,],[555,666,77,8],...]
        function isStructure2(arr) {
            // 假设至少有一个子数组不是两个元素，然后检查是否所有子数组长度都不相同（为了简化，这里只与第一个子数组长度比较）
            // 注意：这个逻辑可以进一步优化，以直接比较所有子数组的长度
            return !isStructure1(arr) && arr.length > 1 && !arr.every((subArr, index, self) => index === 0 ? true : subArr.length === self[0].length);
        }

        // 检查是否为结构3：a=[[[123,2],[456,5],...],[[1123,2],[1456,5],...]]
        function isStructure3(arr) {
            // 检查每个子数组是否都是数组，并且每个子子数组都有两个元素
            return arr.every(subArr => Array.isArray(subArr) && subArr.every(subSubArr => subSubArr.length === 2));
        }

        // 根据判断结果返回相应的标识
        if (isStructure1(arr)) {
            return 1; // 结构1
        } else if (isStructure2(arr)) {
            return 2; // 结构2
        } else if (isStructure3(arr)) {
            return 3; // 结构3
        } else {
            // 如果不符合以上三种结构中的任何一种，则返回0或其他标识（这里为了简洁，返回0并抛出错误）
            console.error('意外的数组结构');
            return 0; // 意外结构
        }
    } 
// -----------

    // ---地归级别函数方法---

    // 定义一个函数，用于实现深拷贝
    deepCopy(obj) {
        // 如果传入的是null或者不是对象，则直接返回
        if (obj === null || typeof obj !== 'object') {
            return obj;
        }

        // 如果是数组，则创建一个新的数组并递归地拷贝每个元素
        if (Array.isArray(obj)) {
            let copyArray = [];
            for (let i = 0; i < obj.length; i++) {
                copyArray[i] = this.deepCopy(obj[i]);
            }
            return copyArray;
        }

        // 如果是对象，则创建一个新的对象并递归地拷贝每个属性
        let copyObj = {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                copyObj[key] = this.deepCopy(obj[key]);
            }
        }
        return copyObj;
    }
    // ---地归级别函数方法---结束
    
    // ---功能部分---结束

}

// import * as dlb from 'duanLiao.js'

dl=new duanLiao(fenData,5500,3,6000);
dl.run();
console.log(dl.fenDuanBiao.toString());
dl.run2();
console.log(dl.fenDuanBiao.toString());
console.log('');
